package com.coldchain.order.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.coldchain.common.enums.DistributionsStatusEnum;
import com.coldchain.common.enums.DistributionsTypeEnum;
import com.coldchain.common.enums.OrderBizTypeEnum;
import com.coldchain.common.exception.base.BusinessException;
import com.coldchain.common.feign.ExpressionFeign;
import com.coldchain.common.msg.BaseResponse;
import com.coldchain.common.msg.ObjectRestResponse;
import com.coldchain.common.util.FunctionUtils;
import com.coldchain.common.vo.BizDispatchingVo;
import com.coldchain.common.vo.BizPersonVo;
import com.coldchain.common.vo.OrderCountResultVo;
import com.coldchain.common.vo.PathsVo;
import com.coldchain.order.entity.*;
import com.coldchain.order.mapper.BizDispatchingOrderMapper;
import com.coldchain.order.service.IBizDispatchingGoodsService;
import com.coldchain.order.service.IBizDispatchingOrderService;
import com.coldchain.order.service.IBizdispatchingPersonService;
import com.coldchain.order.service.IOrderService;
import com.fangliai.core.context.BaseContextHandler;
import com.fangliai.core.entitiy.PageResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 配送订单 服务实现类
 * </p>
 *
 * @author fangliai
 * @since 2018-11-14
 */
@Service
public class BizDispatchingOrderServiceImpl extends ServiceImpl<BizDispatchingOrderMapper, BizDispatchingOrder> implements IBizDispatchingOrderService {
    private static final Logger log= LoggerFactory.getLogger(BizDispatchingOrderServiceImpl.class);

    @Autowired
    private ExpressionFeign expressionFeign;

    @Autowired
    private IOrderService orderService;

    @Autowired
    private IBizDispatchingGoodsService bizDispatchingGoodsService;
    @Autowired
    private IBizdispatchingPersonService bizdispatchingPersonService;

    @Override
    public List<BizDispatchingVo> getDispatchingOrderList(OrderSearch search) {
        QueryWrapper queryWrapper=search.initWrapper();
        queryWrapper.orderByAsc("bp.sort");
        return baseMapper.getBizOrderList(queryWrapper);
    }

    @Override
    public PageResponse<BizDispatchingVo> getDispatchingOrderPage(OrderSearch search) {
        QueryWrapper queryWrapper=search.initWrapper();
        queryWrapper.orderByAsc("bp.sort");
        return new PageResponse<BizDispatchingVo>(baseMapper.getBizOrderList(search.initPage(),queryWrapper));
    }

    @Override
    public PageResponse<BizDispatchingVo> getSimpleOrderPage(OrderSearch search) {
         QueryWrapper queryWrapper=search.initWrapper();
         queryWrapper.orderByAsc("bp.sort");
          IPage<BizDispatchingVo> pages=baseMapper.getSimpleOrderList(search.initPage(),queryWrapper);
          return new PageResponse<BizDispatchingVo>(pages);
    }

    @Override
    public List<BizDispatchingVo> getSimpleOrderList(OrderSearch search) {
        QueryWrapper queryWrapper=search.initWrapper();
        queryWrapper.orderByAsc("bp.sort");
        return baseMapper.getBizOrderList(queryWrapper);
    }

    @Override
    @Transactional
    public BaseResponse createOrder(BizDistributionOrderFromBean orderFromBean) throws Exception {

        if(orderFromBean.getPlaceofreceipts()==null || orderFromBean.getPlaceofreceipts().isEmpty()){
            return new ObjectRestResponse<>().error("请选择取货点");
        }
        if(orderFromBean.getDistributions()==null || orderFromBean.getDistributions().isEmpty()){
            return new ObjectRestResponse<>().error("请选配送点");
        }
        try {
            computeOrderKm(orderFromBean);
            computOrderMoney(orderFromBean);
        }catch (Exception e){
            log.error("订单计算异常.error:{}",e.getMessage());
            return new ObjectRestResponse<>().error(e.getMessage());
        }
        try {
            saveOrder(orderFromBean);
        }catch (Exception e){
            log.error("create order error{}",e.getMessage());
            throw new BusinessException("订单创建失败");
        }

        return new ObjectRestResponse<>(orderFromBean).succeed("ok");

    }

    @Override
    public Object getOrderDetail(String orderId) {
        OrderSearch orderSearch=new OrderSearch();
        orderSearch.setOrderid(orderId);
        QueryWrapper wrapper=orderSearch.initWrapper();
        wrapper.orderByAsc(OrderSearch.ORDER_BY_SORT);
        List<BizDispatchingVo> orders= baseMapper.getBizOrderList(wrapper);
        if(orders.size()==0){
            return null;
        }else {
            BizDispatchingVo bizDispatchingVo=orders.get(0);
            computeNextTask(bizDispatchingVo);
            return orders.get(0);
        }
    }

    @Override
    public BaseResponse getNextTask(String orderId) {
       BizDispatchingOrder order=getById(orderId);
       if(!order.getCysId().equals(BaseContextHandler.getCysID())){
           log.error("this order is not cys[{}]",orderId);
           return new ObjectRestResponse<>().error("找不到订单");
       }
        if(StringUtils.isEmpty(order.getDriverId())){
            log.error("this order is not dispatch[{}]",orderId);
            return new ObjectRestResponse<>().error("该订单还未派送");
        }
       if(!order.getDriverId().equals(BaseContextHandler.getUserID())){
           log.error("this order is not driver[{}]",orderId);
           return new ObjectRestResponse<>().error("找不到订单");
       }
       if(DistributionsStatusEnum.FINISH.getValue().equals(order.getStatus())){
           return new ObjectRestResponse<>().data(-1).succeed("ok");
       }
       int currentIndex=currentPerson(orderId);
        return new ObjectRestResponse<>().data(currentPerson(orderId)).succeed("");
    }

    @Override
    @Transactional
    public BaseResponse doNext(String uid, String orderId, Integer sort, String receipts, String accessorys)throws Exception{
        BizDispatchingOrder order=getById(orderId);
        if(order==null || !order.getDriverId().equals(uid)){
            if(log.isWarnEnabled()){
                log.warn("this order[{}] is not user[{}]",order,uid);
            }
            return new ObjectRestResponse<>().error("没有找到订单号");
        }
        BizdispatchingPerson person=new BizdispatchingPerson();
        person.setAccessorys(accessorys);
        person.setReceipts(receipts);
        return completeTask(orderId,sort,person,true);
    }

    @Override
    public BaseResponse reportError(String uid, String orderId, Integer currentIndex, String receipts, Integer errorCode, String errorMsg)throws Exception {
        BizDispatchingOrder order=getById(orderId);
        if(order==null ||!order.getDriverId().equals(uid)){
            if(log.isWarnEnabled()){
                log.warn("this order[{}] is not user[{}]",order,uid);
            }
            return new ObjectRestResponse<>().error("没有找到订单号");
        }
        BizdispatchingPerson person=new BizdispatchingPerson();
        person.setReceipts(receipts);
        person.setErrorCode(errorCode);
        person.setErrorMsg(errorMsg);
        return completeTask(orderId,currentIndex,person,false);
    }
    /**
     * 完成任务.
     * 根据不同的节点即行业务处理.
     * @param orderId
     * @param currentNode
     * @param currentPerson
     * @param isOk
     * @return
     * @throws Exception
     */
    private BaseResponse completeTask(String orderId,int currentNode,BizdispatchingPerson currentPerson,boolean isOk)throws Exception{
            List<BizdispatchingPerson> persons=getPersons(orderId);
            if(currentNode>0){//上一个任务是否已完成
                BizdispatchingPerson lastPerson=persons.get(currentNode-1);
                if(DistributionsStatusEnum.WAIT_DELIVER.getValue().equals(lastPerson)){
                     if(log.isWarnEnabled()){
                         log.warn("this last task is not finish.[order:{},currentNode:{}]",orderId,currentNode);
                     }
                     return new ObjectRestResponse<>().error("还有未完成的配送任务");
                }
            }
            if(!DistributionsStatusEnum.WAIT_DELIVER.getValue().equals(persons.get(currentNode).getPersonStatus())){//重复提交订单
                if(log.isWarnEnabled()){
                    log.warn("this order repeat,[orerid:{},currentNode:{}]",orderId,currentNode);
                }
                return new ObjectRestResponse<>().data(currentNode==persons.size()-1?-1:currentNode+1).succeed("ok");
            }
            currentPerson.setBizPersonId(persons.get(currentNode).getBizPersonId());
            currentPerson.setPersonStatus(isOk?DistributionsStatusEnum.FINISH.getValue():DistributionsStatusEnum.ERROR.getValue());
            try {
                if(!isOk && currentNode==0){//取货异常直接结束订单
                    updateOrderStatus(orderId,DistributionsStatusEnum.ERROR,currentPerson.getErrorCode(),currentPerson.getErrorMsg());
                }
                bizdispatchingPersonService.updateById(currentPerson);
            }catch (Exception e){
                if(log.isErrorEnabled()){
                    log.error("complete task error:{}",e.getMessage());
                }
                throw new Exception("服务器异常");
            }
            int nextNode=currentNode==persons.size()-1?-1:currentNode+1;

            if(nextNode<0){ //订单配送完成
                updateOrderStatus(orderId,DistributionsStatusEnum.FINISH,currentPerson.getErrorCode(),currentPerson.getErrorMsg());
            }
        return new ObjectRestResponse<>().data(nextNode).succeed("ok");
    }

    /**
     * 更改订单状态
     * @param orderId
     * @param statusEnum
     * @param errorCode
     * @param errorMsg
     * @throws Exception
     */
    private void updateOrderStatus(String orderId,DistributionsStatusEnum statusEnum,Integer errorCode,String errorMsg)throws Exception{
        BizDispatchingOrder order=getById(orderId);
        order.setStatus(statusEnum.getValue());
        order.setErrorCode(errorCode);
        order.setErrorMsg(errorMsg);
        if(statusEnum.equals(DistributionsStatusEnum.FINISH)){

        }
        updateById(order);
    }

    /**
     * 根据订单号计算当前任务节点
     * @param orderId
     * @return
     */
    private Integer currentPerson(String orderId){
        List<BizdispatchingPerson>  persons=getPersons(orderId);
        int currentIndex=-1;
        for (int i = 0; i < persons.size(); i++) {
            if(DistributionsStatusEnum.WAIT_DELIVER.getValue().equals(persons.get(i).getPersonStatus())){
                currentIndex=i;
                break;
            }
        }
        return  currentIndex;
     }

    /**
     * 获取当前所有配送点集合包括取货点
     * @param orderId
     * @return
     */
     private  List<BizdispatchingPerson> getPersons(String orderId){
         QueryWrapper queryWrapper=new QueryWrapper();
         queryWrapper.eq("orderId",orderId);
         queryWrapper.orderByAsc(    "sort");
         return bizdispatchingPersonService.list(queryWrapper);
     }
    /**
     * 计算下一步配送任务
     * @param bizDispatchingVo
     */
    private void computeNextTask(BizDispatchingVo bizDispatchingVo){
        bizDispatchingVo.setCurrentIndex(-1);
        for(int i=0;i<bizDispatchingVo.getPersons().size();i++){
            if(DistributionsStatusEnum.WAIT_DELIVER.getValue().equals(bizDispatchingVo.getPersons().get(i).getPersonStatus())){
                bizDispatchingVo.setCurrentIndex(i);
                return;
            }
        }
    }

    private void saveOrder(BizDistributionOrderFromBean fromBean)throws Exception{
        Order order=new Order();
        order.setChannel(1);
        order.setBizType(OrderBizTypeEnum.DISTRIBUTION.getValue());
        order.setCompanyId(BaseContextHandler.getCommpanyId());
        order.setContent(OrderBizTypeEnum.DISTRIBUTION.getDes());
        order.setTitle(OrderBizTypeEnum.DISTRIBUTION.getDes());
        order.setCreateTime(new Date());
        order.setPrice(fromBean.getAmount());
        orderService.save(order);
        BizDispatchingOrder dispatchingOrder=fromBean;
        dispatchingOrder.setOrderId(order.getOrderId());
        dispatchingOrder.setCreateTime(new Date());
        dispatchingOrder.setTaxes(BigDecimal.ZERO);
        save(dispatchingOrder);
        List<BizPersonVo> bizPersonVos=fromBean.getPlaceofreceipts();
        bizPersonVos.addAll(fromBean.getDistributions());
        List<BizdispatchingPerson> personLists= JSONArray.parseArray(JSONArray.toJSONString(bizPersonVos),BizdispatchingPerson.class);
        personLists.forEach((v->{
            v.setPersonStatus(DistributionsStatusEnum.WAIT_DELIVER.getValue());
            v.setOrderId(order.getOrderId());
        }));
        bizdispatchingPersonService.saveBatch(personLists);
        List<BizDispatchingGoods> goodsList=new ArrayList<>();
        for (int i=0;i<fromBean.getDistributions().size();i++ ){
            List<BizDispatchingGoods> goods=JSONArray.parseArray(JSONArray.toJSONString(fromBean.getDistributions().get(i).getGoodsList()),BizDispatchingGoods.class);
            for (BizDispatchingGoods g: goods ) {
                g.setBizPersonId(personLists.get(i+1).getBizPersonId());
            }
            goodsList.addAll(goods);
        }
        bizDispatchingGoodsService.saveBatch(goodsList);
    }



    /**
     * 计算订单里程
     * @param orderFromBean
     * @throws Exception
     */
    private void computeOrderKm(BizDistributionOrderFromBean orderFromBean)throws Exception{
        //保留排序后的数据
        List<BizPersonVo> newreceivedAddrs = new ArrayList<>();
        BizPersonVo placeofreceipt=orderFromBean.getPlaceofreceipts().get(0);
        if(orderFromBean.getOrderType().equals(DistributionsTypeEnum.INTRA.getValue())){
            boolean isok=true;
            for (int i=0;i<orderFromBean.getDistributions().size();i++){
                if(!orderFromBean.getDistributions().get(i).getAdecode().equals(placeofreceipt.getAdecode())){
                    isok=false;
                    break;
                }
            }
            if(!isok){
                throw new Exception("超出同城配送范围");
            }
        }

        sortNode(orderFromBean.getDistributions(),placeofreceipt.getLongitude(),placeofreceipt.getLatitude(),newreceivedAddrs,1,0);
        //途径的参数
        StringBuffer waypoints = new StringBuffer();
        for(BizPersonVo person:newreceivedAddrs){
            waypoints.append(person.getLongitude()).append(",").append(person.getLatitude()).append(";");
        }
        //送达最后一个为终点
        BizPersonVo person = newreceivedAddrs.get(newreceivedAddrs.size()-1);
        //起点参数
        String origin = placeofreceipt.getLongitude()+","+placeofreceipt.getLatitude();
        //终点点参数
        String destination = person.getLongitude()+","+person.getLatitude();
        PathsVo path = FunctionUtils.driving(origin, destination,19,waypoints.toString());
        orderFromBean.setOrderKm(path.getDistance()/1000);
        orderFromBean.setPredictKm(orderFromBean.getOrderKm());

        orderFromBean.setDistributions(newreceivedAddrs);
    }

    /**
     * 计算订单阶格
     * @param orderFromBean
     * @throws Exception
     */
    private void computOrderMoney(BizDistributionOrderFromBean orderFromBean)throws Exception{

        ObjectRestResponse<OrderCountResultVo> restResponse=expressionFeign.getOrderPrice(
                orderFromBean.getOrderKm().intValue(),
                orderFromBean.getDistributions().size(),
                orderFromBean.getPlaceofreceipts().get(0).getAdecode(),
                orderFromBean.getCarTypeId(),
                orderFromBean.getOrderType().equals(DistributionsTypeEnum.INTER.getValue())
        );
        if(restResponse.getStatus()!=200){
            throw new Exception(restResponse.getMessage());
        }
        orderFromBean.setDiscount(restResponse.getData().getDiscounts());
        orderFromBean.setExceedPrice(restResponse.getData().getExceedPrice());
        orderFromBean.setExceedKm(restResponse.getData().getExceedKm());
        orderFromBean.setInitiatePrice(BigDecimal.valueOf(restResponse.getData().getUsePrice()));
        orderFromBean.setAmount(BigDecimal.valueOf(restResponse.getData().getOrderPrice()));
        orderFromBean.setTotlaPrice(BigDecimal.valueOf(restResponse.getData().getOrderPrice()));
        System.out.println(JSONObject.toJSONString(restResponse));
    }
    /**
     * 排序收货点
     * @param receivedAddrs
     * @param longitude
     * @param latitude
     * @param list
     */
    private void sortNode(List<BizPersonVo> receivedAddrs, double longitude, double latitude, List<BizPersonVo> list, int sort, double min){
        int index = 1;

        if(receivedAddrs.size() > 1){
            for(int x = 0 ; x < receivedAddrs.size();x++){
                BizPersonVo person = receivedAddrs.get(x);
                String origin = longitude+","+latitude;
                String destination =person.getLongitude()+","+person.getLatitude();
                PathsVo path = FunctionUtils.driving(origin, destination,19,"");
                double km = path.getDistance();
                Double duration = path.getDistance()*1000;
                if(list.isEmpty()){
                    Date predictFinishTime = new Date(System.currentTimeMillis()+(duration.intValue()));
                    person.setPredictFinishTime(predictFinishTime);
                }else{
                    BizPersonVo predict = list.get(list.size()-1);
                    Date predictFinishTime = new Date(predict.getPredictFinishTime().getTime()+(duration.intValue()));
                    person.setPredictFinishTime(predictFinishTime);
                }
                person.setPredictKm(km/1000);
                if(min==0){
                    min = km;
                    index = x;
                }else if(km<=min){
                    min = km;
                    index = x;
                }
            }
            BizPersonVo last = receivedAddrs.get(index);
            last.setSort(sort);
            sort++;
            list.add(last) ;
            receivedAddrs.remove(index) ;
            sortNode(receivedAddrs,last.getLongitude(),last.getLatitude(),list,sort,min);
        }else{
            BizPersonVo person = receivedAddrs.get(0);
            String origin = longitude+","+latitude;
            String destination =person.getLongitude()+","+person.getLatitude();
            PathsVo path = FunctionUtils.driving(origin, destination,19,"");
            Double duration = path.getDistance()*1000;
            if(list.isEmpty()){
                Date predictFinishTime = new Date(System.currentTimeMillis()+(duration.intValue()));
                person.setPredictFinishTime(predictFinishTime);
                person.setPredictKm(path.getDistance()/1000);
            }else{
                BizPersonVo predict = list.get(list.size()-1);
                Date predictFinishTime = new Date(predict.getPredictFinishTime().getTime()+(duration.intValue()));
                person.setPredictFinishTime(predictFinishTime);
            }
            person.setSort(sort);
            sort++;
            receivedAddrs.remove(0) ;
            list.add(person) ;
        }

    }
}
